package es.udima.geo.geoserver.persistence;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.swing.border.EtchedBorder;

import es.udima.geo.geoserver.entities.GpsData;
import es.udima.geo.geoserver.entities.GpsDataFilter;

public class GpsDataDAO extends GenericDAO {

    public GpsDataDAO() {
    }

    /**
     * 
     * @return
     */
    public List<GpsData> retrieveGpsData(GpsDataFilter filter) {

	EntityManager em = createEntityManager();

	List<GpsData> res = new ArrayList<GpsData>();

	try {
	    CriteriaBuilder cb = em.getCriteriaBuilder();
	    CriteriaQuery<GpsData> cq = cb.createQuery(GpsData.class);
	    Root<GpsData> r = cq.from(GpsData.class);

	    Predicate pred = cb.conjunction();

	    if (filter.getUserId() != null) {
		Predicate pd = cb.equal(r.get("userId"), filter.getUserId());
		pred = cb.and(pred, pd);
	    }

	    if (filter.getInitDate() != null) {
		Calendar d = Calendar.getInstance();
		d.setTime(filter.getInitDate().getTime());
		d.set(Calendar.HOUR_OF_DAY, 0);
		d.set(Calendar.MINUTE, 0);
		d.set(Calendar.SECOND, 0);
		d.set(Calendar.MILLISECOND, 0);
		Predicate pd = cb.greaterThan(r.get("fetchTime").as(Calendar.class), d);
		pred = cb.and(pred, pd);
	    }

	    if (filter.getEndDate() != null) {
		Calendar d = Calendar.getInstance();
		d.setTime(filter.getEndDate().getTime());
		d.set(Calendar.HOUR_OF_DAY, 23);
		d.set(Calendar.MINUTE, 59);
		d.set(Calendar.SECOND, 59);
		d.set(Calendar.MILLISECOND, 999);
		Predicate pd = cb.lessThan(r.get("fetchTime").as(Calendar.class), d);
		pred = cb.and(pred, pd);
	    }

	    cq.select(r).where(pred);
	    TypedQuery<GpsData> tq = em.createQuery(cq);
	    res = tq.getResultList();
	} catch (Exception e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	} finally {
	    em.close();
	}

	return res;
    }

    /**
     * Devuelve la fecha en la cual se han recibido los ultimos datos gps del
     * usuario con id userId.
     * 
     * @param userId
     * @return
     */
    public Calendar retrieveLastDayGpsData(String userId) {
	EntityManager em = createEntityManager();

	Calendar res = null;
	try {
	    CriteriaBuilder cb = em.getCriteriaBuilder();
	    CriteriaQuery<Timestamp> cq = cb.createQuery(Timestamp.class);
	    Root<GpsData> r = cq.from(GpsData.class);

	    cq.select(cb.greatest(r.get("fetchTime").as(Timestamp.class)));
	    cq.where(cb.equal(r.get("userId"), userId));

	    TypedQuery<Timestamp> tq = em.createQuery(cq);
	    Timestamp ts = tq.getSingleResult();

	    if (ts != null) {
		res = Calendar.getInstance();
		res.setTimeInMillis(ts.getTime());
		res.set(Calendar.HOUR_OF_DAY, 0);
		res.set(Calendar.MINUTE, 0);
		res.set(Calendar.SECOND, 0);
		res.set(Calendar.MILLISECOND, 0);
	    }
	    
	} catch (Exception e) {
	    e.printStackTrace();
	} finally {
	    em.close();
	}
	
	return res;
    }

    /**
     * 
     * @param gpsData
     */
    public void storeGpsData(List<GpsData> gpsData) {
	EntityManager em = createEntityManager();

	try {
	    EntityTransaction et = em.getTransaction();
	    et.begin();
	    
	    try {
	        for(GpsData gd : gpsData) {
	            em.persist(gd);
	        }
	        et.commit();
	    } catch (Exception e) {
	        et.rollback();
	        throw e;
	    } 
	    
	} catch (Exception e) {
	    e.printStackTrace();
	} finally {
	    em.close();
	}
    }

}
